// $Id: pstring.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_IMPL_PSTRING_HPP
#define XPCOM_IMPL_PSTRING_HPP

#include <xpcom/config.hpp>
#include <boost/noncopyable.hpp>
#include <xpcom/types.hpp>
#include <xpcom/string.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {
namespace impl {

//
// XPCOM implementation argument translators.
// Note: The out/inout arguments must not be null.
//
// pstr_in(const char*) --> const char*
// pstr_out(char**) --> string&
// pstr_inout(char**) --> string&
// pwstr_in(const wchar*) --> const wchar*
// pwstr_out(wchar**) --> wstring&
// pwstr_inout(wchar**) --> wstring&
//
// Following functions are for pstrings with size_is and, optionally length_is.
//
// pstr_out_size(char**, size*, length*) --> string&
// pstr_out_size2(char**, size2*) --> string&
// pstr_inout_size(char**, size*, length*) --> string&
// pstr_inout_size2(char**, size2*) --> string&
// pwstr_out_size(wchar**, size*, length*) --> wstring&
// pwstr_out_size2(wchar**, size2*) --> wstring&
// pwstr_inout_size(wchar**, size*, length*) --> wstring&
// pwstr_inout_size2(wchar**, size2*) --> wstring&
//
//
// Fix for some interface like nsIBinaryInputStream which uses input [size_is]
// param for output string, which is supported through pstring_out_isize2,
// call it on pstring parameter.
//
// FIXME other similar condition is not handled, report it you have weird
// interface like this, ...
//

template <typename CharT>
XPCOM_FORCEINLINE
const CharT* pstring_in(const CharT* s)
{
    return s;
}

template <typename CharT>
class pstring_out : boost::noncopyable
{
public:
    XPCOM_DECL explicit pstring_out(CharT** s);
    XPCOM_DECL ~pstring_out();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

    XPCOM_FORCEINLINE
    void operator=(basic_string<CharT> retval)
    {
        val_.swap(retval);
    }

private:
    CharT** s_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_out_size : boost::noncopyable
{
    typedef uint32_t size_type;
public:
    XPCOM_DECL pstring_out_size(
            CharT** s, size_type* size, size_type* length);
    XPCOM_DECL ~pstring_out_size();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

    XPCOM_FORCEINLINE
    void operator=(basic_string<CharT> retval)
    {
        val_.swap(retval);
    }

private:
    CharT** s_;
    size_type* size_;
    size_type* length_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_out_size2 : boost::noncopyable
{
    typedef uint32_t size_type;
public:
    XPCOM_DECL pstring_out_size2(CharT** s, size_type* size);
    XPCOM_DECL ~pstring_out_size2();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

    XPCOM_FORCEINLINE
    void operator=(basic_string<CharT> retval)
    {
        val_.swap(retval);
    }

private:
    CharT** s_;
    size_type* size_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_inout : boost::noncopyable
{
public:
    XPCOM_DECL explicit pstring_inout(CharT** s);
    XPCOM_DECL ~pstring_inout();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

private:
    CharT** s_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_inout_size : boost::noncopyable
{
    typedef uint32_t size_type;
public:
    XPCOM_DECL pstring_inout_size(
            CharT** s, size_type* size, size_type* length);
    XPCOM_DECL ~pstring_inout_size();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

private:
    CharT** s_;
    size_type* size_;
    size_type* length_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_inout_size2 : boost::noncopyable
{
    typedef uint32_t size_type;
public:
    XPCOM_DECL pstring_inout_size2(CharT** s, size_type* size);
    XPCOM_DECL ~pstring_inout_size2();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

private:
    CharT** s_;
    size_type* size_;
    basic_string<CharT> val_;
};

template <typename CharT>
class pstring_out_isize2 : boost::noncopyable
{
    typedef uint32_t size_type;
public:
    XPCOM_DECL pstring_out_isize2(CharT** s, size_type size);
    XPCOM_DECL ~pstring_out_isize2();

    XPCOM_FORCEINLINE
    operator basic_string<CharT>&()
    {
        return val_;
    }

    XPCOM_FORCEINLINE
    void operator=(basic_string<CharT> retval)
    {
        val_.swap(retval);
    }

private:
    CharT** s_;
    basic_string<CharT> val_;
    size_type size_;
};

// For direct call
XPCOM_FORCEINLINE
const char* pstr_in(const char* s)
{
    return s;
}

XPCOM_FORCEINLINE
const wchar* pwstr_in(const wchar* s)
{
    return s;
}

typedef pstring_out<char>           pstr_out;
typedef pstring_out<wchar>          pwstr_out;
typedef pstring_out_size<char>      pstr_out_size;
typedef pstring_out_size<wchar>     pwstr_out_size;
typedef pstring_out_size2<char>     pstr_out_size2;
typedef pstring_out_size2<wchar>    pwstr_out_size2;
typedef pstring_inout<char>         pstr_inout;
typedef pstring_inout<wchar>        pwstr_inout;
typedef pstring_inout_size<char>    pstr_inout_size;
typedef pstring_inout_size<wchar>   pwstr_inout_size;
typedef pstring_inout_size2<char>   pstr_inout_size2;
typedef pstring_inout_size2<wchar>  pwstr_inout_size2;
typedef pstring_out_isize2<char>    pstr_out_isize2;
typedef pstring_out_isize2<wchar>   pwstr_out_isize2;

} // namespace xpcom::impl
} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_IMPL_PSTRING_HPP
